package Activemq;

import Pathall.AStarPlanner;
import Pathall.BFS;
import Pathall.BidirectionalAStarPlanner;
import Pathall.PathPlanner;
import Redis.Rdo;
import jakarta.jms.Message;
import jakarta.jms.TextMessage;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Navigator extends C2Component{
    //消息队列的名称么
    int mapWidth;
    int mapHeight;
    private String queueName;
    private Redis.Rdo rdo;
    private int Statue;//设置小车状态
    // 添加路径规划器选择
    private PathPlanner pathPlanner;
    // 在 Navigator.java 中添加成员变量
    private RegionManager regionManager;
    //id 代表是小车的id
    /**
     * 构造函数
     * @param host 主机地址
     * @param port 端口
     * @param user 用户
     * @param pwd 密码
     */

    private ExecutorService executorService; // 新增线程池

    // 在构造函数中初始化 RegionManager
    public Navigator(String host, int port, String user, String pwd, String queueName, String ip, int ipport) {
        super(host, port, user, pwd);
        this.queueName = "navigator";
        this.executorService = Executors.newFixedThreadPool(10);

        // 初始化 Redis.Rdo
        try {
            this.rdo = new Redis.Rdo(ip, ipport);
            this.rdo.connect();

            // 检查 rdo 是否成功初始化
            if (this.rdo == null) {
                throw new IllegalStateException("Redis.Rdo initialization failed");
            }

            // 获取地图宽度和高度
            this.mapWidth = this.rdo.getMapwidth();
            this.mapHeight = this.rdo.getMapheight();

            // 初始化 RegionManager
            this.regionManager = new RegionManager(mapWidth, mapHeight);
        } catch (Exception e) {
            throw new IllegalStateException("Failed to initialize Redis.Rdo: " + e.getMessage(), e);
        }
    }


    private int startX;  // 新增：保存起点x坐标
    private int startY;  // 新增：保存起点y坐标





    @Override
    public void run() {
        try {
            sender = new Sender(host, port, user, pwd);
            sender.startWork();
            reciever = new Reciever(host, port, user, pwd, queueName);
            reciever.startListern();
            toWork = true;

            while (toWork) {
                if (reciever != null && !reciever.msgList.isEmpty()) {
                    // 提交任务到线程池
                    Message receivedMessage = reciever.msgList.poll();
                    String carId = ((TextMessage) receivedMessage).getText();
                    String id = carId.replaceAll("card", ""); // 去掉前缀 "card"
                    //判断是否能够
                    String routeListKey = "car:" + carId + ":tasks";
                    // 不加锁，直接检查是否存在任务
                    Boolean keyExists = rdo.probe(routeListKey);
                    if(!keyExists)
                        executorService.submit(() -> processCar(id)); // 使用Lambda表达式
                }
                Thread.sleep(100);
            }
        } catch (Exception e) {
            System.err.println("Critical error: " + e.getMessage());
        } finally {
            executorService.shutdown(); // 关闭线程池
        }
    }


    private void processCar(String carId) {
        // 如果已经在处理这辆车，直接跳过
        try {
            // 获取当前车辆位置
            int[] currentPosition = Rdo.getCarPosition(carId);
            if (currentPosition == null) {
                System.err.println("无法获取车辆 " + carId + " 的位置");
                return;
            }
            // 判断是否全图已经照亮
            long totalCells = mapWidth * mapHeight;
            long illuminatedCount = rdo.getIlluminatedCount();

            if (illuminatedCount >= totalCells) {
                System.out.println("✅ 全图已照亮，车 " + carId + " 不需要执行任务");
                return;
            }

            // 计算目标位置和路径
            int[] targetPosition = findOptimalTarget(carId);
            // 处理找不到目标点的情况
            if (targetPosition == null) {
                System.out.println("⚠️ 车 " + carId + " 未找到可探索目标（可能全图已照亮）");
                return;
            }
            System.out.println("车"+carId+" 起点："+currentPosition[0]+","+currentPosition[1]+" 目标："+targetPosition[0]+","+targetPosition[1]);
            //List<int[]> plannedPath = aStarPath(currentPosition, targetPosition);
            String type=rdo.getalgotithm();
            System.out.println(type);
            if(type.equals("A*"))
                this.pathPlanner=new AStarPlanner();
            else if(type.equals("AA*"))
                this.pathPlanner=new BidirectionalAStarPlanner();
            else if(type.equals("BFS"))
                this.pathPlanner=new BFS();
            else
                this.pathPlanner=new AStarPlanner();
            List<int[]> plannedPath=this.pathPlanner.findPath( currentPosition,
                    targetPosition,
                    rdo,
                    mapWidth,
                    mapHeight);
            // 保存路径到Redis
            savePathToRedis(carId, plannedPath);
        } catch (Exception e) {
            System.err.println("处理车辆 " + carId + " 时出错: " + e.getMessage());
        }
    }

    // 修改 findOptimalTarget 方法
    private int[] findOptimalTarget(String carId) {
        int[] pos = Rdo.getCarPosition(carId);
        if (pos == null) return null;
        int startX = pos[0], startY = pos[1];

        // 更新车辆所在的区域
        regionManager.assignCarToRegion(carId, startX, startY);

        // 使用 RegionManager 查找最优目标
        int[] target = regionManager.findOptimalTarget(startX, startY, carId, rdo);

        if (target != null) {
            // 标记该点为已照亮
            regionManager.markCellIlluminated(target[0], target[1]);
        }

        return target;
    }



    private List<int[]> aStarPath(int[] start, int[] end) {
        // 参数检查
        if (start == null || end == null) {
            System.err.println("起点或终点为空");
            return new ArrayList<>();
        }

        if (!isValidCoordinate(end[0], end[1])) {
            System.err.println("目标点超出地图范围：" + end[0] + "," + end[1]);
            return new ArrayList<>();
        }

        // 创建起始节点和目标节点
        Node startNode = new Node(null, start[0], start[1]);
        Node goalNode = new Node(null, end[0], end[1]);

        // 特殊处理：如果起点就是终点
        if (startNode.equals(goalNode)) {
            return Collections.singletonList(new int[]{start[0], start[1]});
        }

        // 初始化数据结构
        PriorityQueue<Node> openList = new PriorityQueue<>();
        Set<String> closedList = new HashSet<>();
        Map<String, Node> nodeCache = new HashMap<>();

        openList.add(startNode);

        while (!openList.isEmpty()) {
            Node currentNode = openList.poll();

            // 找到目标节点
            if (currentNode.equals(goalNode)) {
                return reconstructPath(currentNode);
            }

            String nodeKey = currentNode.getKey();
            if (closedList.contains(nodeKey)) continue;
            closedList.add(nodeKey);

            // 探索所有可能方向
            for (Direction dir : Direction.values()) {
                int neighborX = currentNode.x + dir.deltaX;
                int neighborY = currentNode.y + dir.deltaY;

                // 跳过无效坐标
                if (!isValidCoordinate(neighborX, neighborY)) continue;

                // 关键修改：仅当不是终点时才检查障碍物
                boolean isGoal = (neighborX == goalNode.x && neighborY == goalNode.y);
                if (!isGoal && rdo.checkobstacle(neighborX, neighborY)) {
                    continue;
                }

                String key = neighborX + "," + neighborY;
                Node neighborNode = nodeCache.getOrDefault(key, new Node(null, neighborX, neighborY));

                // 计算移动代价
                double g = currentNode.g + 1;
                double h = heuristic(neighborX, neighborY, goalNode.x, goalNode.y);
                double f = g + h;

                // 如果找到更优路径或新节点
                if (!nodeCache.containsKey(key) || f < neighborNode.f) {
                    neighborNode.g = g;
                    neighborNode.h = h;
                    neighborNode.f = f;
                    neighborNode.parent = currentNode;

                    if (!openList.contains(neighborNode)) {
                        openList.add(neighborNode);
                    }
                    nodeCache.put(key, neighborNode);
                }
            }
        }

        System.err.println("未找到可行路径");
        return new ArrayList<>(); // 返回空路径
    }


    // 自定义启发函数
    private double heuristic(int x1, int y1, int x2, int y2) {
        // 曼哈顿距离（适合四方向）
        return Math.abs(x1 - x2) + Math.abs(y1 - y2);

        // 欧几里得距离（适合八方向）
        // return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }


    // 路径重建方法
    private List<int[]> reconstructPath(Node endNode) {
        List<int[]> path = new ArrayList<>();
        Node currentNode = endNode;
        while (currentNode != null) {
            path.add(0, new int[]{currentNode.x, currentNode.y});
            currentNode = currentNode.parent;
        }
        return path;
    }

    private boolean isStartNode(Node node) {
        return node.x == startX && node.y == startY;
    }


    // 辅助方法：坐标有效性检查
    private boolean isValidCoordinate(int x, int y) {
        return x >= 0 && x < mapWidth && y >= 0 && y < mapHeight;
    }

    // 方向枚举
    private enum Direction {
        UP(-1, 0),
        DOWN(1, 0),
        LEFT(0, -1),
        RIGHT(0, 1);

        public final int deltaX;
        public final int deltaY;

        Direction(int deltaX, int deltaY) {
            this.deltaX = deltaX;
            this.deltaY = deltaY;
        }
    }


    private void savePathToRedis(String carId, List<int[]> plannedPath) {
        System.out.println("1");
        if (plannedPath == null || plannedPath.isEmpty()) {
            System.out.println("Empty path, skip saving to Redis for car " + carId);
            return;
        }

        try {
            String redisKey = "car:" + carId + ":tasks";

                System.out.println(redisKey);

            // 将每个坐标点转为独立字符串，存入 Redis List
            for (int[] point : plannedPath) {
                String pointStr = point[0] + " " + point[1];
                System.out.println(pointStr);
                rdo.lpush(redisKey, pointStr); // 左端插入（FIFO 顺序）
            }


            System.out.println("Path saved to Redis for car " + carId);
        } catch (Exception e) {
            System.err.println("Failed to save path to Redis: " + e.getMessage());
        }
    }


    public void shutdown() {
        toWork = false;
        executorService.shutdownNow();
        if (rdo != null) rdo.close();
    }



















}
